/* Gauge - Performance Measurement Framework for Mobile Platforms
 * Copyright (C) 2013, Juha Hytonen <juha.a.hytonen@gmail.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.gauge;

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;

/**
 * SocketMonitor monitors a socket waiting for data. It periodically
 * sends a PollCharacter to check if the connection is still alive.
 */
public final class SocketMonitor extends Thread {

    /**
     * SocketMonitor's callback interface. SocketMonitor notifies 
     * listener of changes in socket's state.
     */
    public interface SocketListener {
        /**
         * Socket has data to be read.
         */
        public void SocketEvent();
        
        /**
         * Socket has been disconnected.
         */
        public void SocketLostEvent();
    }

    /**
     * Default constructor.
     * 
     * @param pListener Listener for socket events.
     * @param pSocket Socket to be monitored.
     * @see SocketListener
     */
    public SocketMonitor(SocketListener pListener, Socket pSocket) {
        assert(pListener != null);
        assert(pSocket != null);

        mListener = pListener;
        try {
            mInput = new InputStreamReader(pSocket.getInputStream());
            mOutput = pSocket.getOutputStream();
        }
        catch(IOException e) {
            mInput = null;
        }
    }

    // Thread ////////////////////////////////////////////////////////////////

    public void run() {
        if(mInput == null) {
            mListener.SocketLostEvent();
            return;
        } // No else.

        while(true) {
            try {
                if (mInput.ready()) {
                    mListener.SocketEvent();
                    break;
                }
                else {
                    // Test if connection is alive. IOException thrown if not.
                    mOutput.write(Protocol.PollCharacter);
                    // Wait for data to come available.
                    sleep(500);
                }
            }
            catch(InterruptedException e) { //sleep()
            }
            catch(IOException e) { // ready(), write()
                mListener.SocketLostEvent();
                break;
            }
        }
    }

    // Private parts. ////////////////////////////////////////////////////

    private SocketListener mListener;
    private InputStreamReader mInput;
    private OutputStream mOutput;
}
